package org.amn.concurrent;

import java.io.IOException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.amn.config.AppConfig;
import org.amn.dto.IndexDTO;
import org.amn.file.FileManager;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * <p>
 * 描述:主控管理者
 * </p>
 *
 * @see
 * @author yangjun1120@gmail.com
 *
 */
public class MainManager {

    private static Logger logger = Logger.getLogger(MainManager.class);

    private IindexQueue<IndexDTO> q;

    private ScheduledExecutorService sses;//扫描

    private ScheduledExecutorService wses;//轮询工作

    private static FileManager fm;

    private final int cpuNum = Runtime.getRuntime().availableProcessors();

    private final int corePoolSize = cpuNum < 9 ? cpuNum : (3 + cpuNum * 5 / 8);//根据cpu数

    private final int maximumPoolSize = (corePoolSize * 2);//*1.5 还是 +2

    private static AppConfig appConfig;

    private final static String CONFIG_FILES = "properties-config.xml";

    private int workerMax = 1;

    private int scannerMax = 1;

    public MainManager() throws IOException {

        if (appConfig == null) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext(CONFIG_FILES);
            appConfig = ctx.getBean(AppConfig.class);
        }

        try {
            fm = new FileManager(appConfig);
        } catch (IOException e) {
            logger.error("init FileManager error ", e);
            throw e;
        }

        sses = Executors.newScheduledThreadPool(1);//thread pool

        wses = Executors.newScheduledThreadPool(corePoolSize);

        int capacity = appConfig.getQueueCapacity();

        q = new IndexBlockingQueue<IndexDTO>(capacity);

        scannerMax = (maximumPoolSize / 5) < 1 ? 1 : (maximumPoolSize / 5);

        workerMax = (maximumPoolSize - 1 - scannerMax) < 0 ? 1 : (maximumPoolSize - 1 - scannerMax);

    }

    public IindexQueue<IndexDTO> getQueue() {
        return q;
    }

    public ScheduledExecutorService getScanScheduledExecutorService() {
        return sses;
    }

    public ScheduledExecutorService getWorkScheduledExecutorService() {
        return wses;
    }

    public void doWork() {

        Dispatcher d = new Dispatcher(fm, scannerMax, q);
        sses.scheduleWithFixedDelay(d, 0, appConfig.getDispatcherDelay(), TimeUnit.SECONDS);

        Backupper c = new Backupper(fm);
        sses.scheduleWithFixedDelay(c, 0, appConfig.getBackupperDelay(), TimeUnit.MINUTES);

        if (logger.isDebugEnabled()) {
            logger.debug("maximumPoolSize:" + maximumPoolSize);
        }

        for (int i = 0; i < workerMax; i++) {
            Worker w = new Worker(fm, q);
            wses.scheduleWithFixedDelay(w, 0, appConfig.getWorkerDelay(), TimeUnit.NANOSECONDS);
        }

    }

    public void shutdown() {
        if (sses != null) {
            sses.shutdownNow();
        }

        if (wses != null) {
            wses.shutdownNow();
        }
    }

    public static void main(String[] args) throws Exception {

        MainManager m = new MainManager();
        m.doWork();

    }
}
